package sql

import (
	"database/sql"

	"github.com/Masterminds/squirrel"
	"github.com/semaphoreui/semaphore/db"
)

func (d *SqlDb) GetAccessKey(projectID int, accessKeyID int) (key db.AccessKey, err error) {
	err = d.getObject(projectID, db.AccessKeyProps, accessKeyID, &key)
	return
}

func (d *SqlDb) GetAccessKeyRefs(projectID int, keyID int) (db.ObjectReferrers, error) {
	return d.getObjectRefs(projectID, db.AccessKeyProps, keyID)
}

func (d *SqlDb) GetAccessKeys(projectID int, options db.GetAccessKeyOptions, params db.RetrieveQueryParams) (keys []db.AccessKey, err error) {
	keys = make([]db.AccessKey, 0)

	q, err := d.makeObjectsQuery(projectID, db.AccessKeyProps, params)

	if err != nil {
		return
	}

	if !options.IgnoreOwner {
		q = q.Where("pe.owner=?", options.Owner)

		switch options.Owner {
		case db.AccessKeyVariable, db.AccessKeyEnvironment:
			q = q.Where(squirrel.Eq{"pe.environment_id": *options.EnvironmentID})
		case db.AccessKeySecretStorage:
			q = q.Where(squirrel.Eq{"pe.storage_id": options.StorageID})
		}
	}

	query, args, err := q.ToSql()

	if err != nil {
		return
	}

	_, err = d.selectAll(&keys, query, args...)

	for i := range keys {
		if keys[i].SourceStorageID == nil && keys[i].Secret == nil {
			keys[i].Empty = true
		}
	}

	return
}

func (d *SqlDb) UpdateAccessKey(key db.AccessKey) error {
	err := key.Validate(key.OverrideSecret)

	if err != nil {
		return err
	}

	var res sql.Result

	var args []any
	query := "update access_key set name=?"
	args = append(args, key.Name)

	if key.OverrideSecret {
		query += ", type=?, secret=?"
		args = append(args, key.Type)
		args = append(args, key.Secret)
	}

	query += " where id=?"
	args = append(args, key.ID)

	query += " and project_id=?"
	args = append(args, key.ProjectID)

	res, err = d.exec(query, args...)

	return validateMutationResult(res, err)
}

func (d *SqlDb) CreateAccessKey(key db.AccessKey) (newKey db.AccessKey, err error) {
	//err = key.SerializeSecret()
	//if err != nil {
	//	return
	//}

	insertID, err := d.insert(
		"id",
		"insert into access_key ("+
			"name, "+
			"type, "+
			"project_id, "+
			"secret, "+
			"environment_id, "+
			"owner, "+
			"storage_id, "+
			"source_storage_id, "+
			"source_storage_key) "+
			"values (?, ?, ?, ?, ?, ?, ?, ?, ?)",
		key.Name,
		key.Type,
		key.ProjectID,
		key.Secret,
		key.EnvironmentID,
		key.Owner,
		key.StorageID,
		key.SourceStorageID,
		key.SourceStorageKey,
	)

	if err != nil {
		return
	}

	newKey = key
	newKey.ID = insertID
	return
}

func (d *SqlDb) DeleteAccessKey(projectID int, accessKeyID int) error {
	return d.deleteObject(projectID, db.AccessKeyProps, accessKeyID)
}

const RekeyBatchSize = 100

func (d *SqlDb) RekeyAccessKeys(oldKey string) (err error) {

	//var globalProps = db.AccessKeyProps
	//globalProps.IsGlobal = true
	//
	//for i := 0; ; i++ {
	//
	//	var keys []db.AccessKey
	//	err = d.getObjects(-1, globalProps, db.RetrieveQueryParams{Count: RekeyBatchSize, Offset: i * RekeyBatchSize}, nil, &keys)
	//
	//	if err != nil {
	//		return
	//	}
	//
	//	if len(keys) == 0 {
	//		break
	//	}
	//
	//	for _, key := range keys {
	//
	//		err = key.DeserializeSecret2(oldKey)
	//
	//		if err != nil {
	//			return err
	//		}
	//
	//		key.OverrideSecret = true
	//		err = d.UpdateAccessKey(key)
	//
	//		if err != nil && !errors.Is(err, db.ErrNotFound) {
	//			return err
	//		}
	//	}
	//}

	return
}
